/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef UTIL_HH
#define UTIL_HH
//! \defgroup util Utilities
//@{~select

#include <stdio.h>
#include <stdlib.h>
#include "../config.h"

// colours
#ifndef DONT_USE_COLORS
#define RED "\033[31m"
#define GREEN "\033[32m"
#define BROWN "\033[33m"
#define BLUE "\033[34m"
#define MAGENTA "\033[35m"
#define CYAN "\033[36m"
#define WHITE "\033[37m"
#define RED_BOLD "\033[1;31m"
#define BLUE_BOLD "\033[1;34m"
#define YELLOW "\033[1;33m"
#define RESET "\033[0m"
#else
#define RED
#define GREEN
#define BROWN
#define BLUE
#define MAGENTA
#define CYAN
#define WHITE
#define RED_BOLD
#define BLUE_BOLD
#define YELLOW
#define RESET
#endif

// util functions
namespace util
{
    // light-weight customized vector implementation
    template<typename T> int inc_vector(T *&v, int &n, int &max, int inc)
    {
	int i=n++;
	if(n>max) {max+=inc; v=(T*)realloc(v, max*sizeof(T));}
	return i;
    }

    template<typename T> void ctor_vector(T *&v, int &n, int &max)
    {
	v=NULL; n=max=0;
    }

    template<typename T> void dtor_vector(T *&v, int &n, int &max)
    {   // does not delete each v item
	if(v) v=(T*)realloc(v, 0); n=max=0;
    }

    template<typename T> void dtor_vector_delete(T *&v, int &n, int &max)
    {
	if(v)
	{
	    for(int i=0; i<n; i++) if(v[i]) delete v[i];
	    v=(T*)realloc(v, 0);
	}
	n=max=0;
    }

    // hash
    unsigned fast_checksum(void *data, int n_data);
};

// logger (singleton)
#define LOG_FILENAME "/tmp/debug.log"
#define LOG_NOSYNC
struct logger
{
    static FILE *file();
};

// debug
#ifdef DEBUG_CC

#if 0
#define LOG_USE_STDERR
#endif
#define DBGFILE               logger::file()

#define DEBUG(fmt, arg...)    do{fprintf(DBGFILE, "["MAGENTA"%s:%s"RESET"] "CYAN""fmt""RESET"\n", \
					 __FILE__, __PRETTY_FUNCTION__ , ##arg);} while(0)
#define DEBUG_FLUSH()         do{fflush(DBGFILE);} while(0)
#define ERROR(fmt, arg...)    do{fprintf(stderr, "["MAGENTA"%s:%s"RESET"] "RED_BOLD""fmt""RESET"\n", \
					 __FILE__, __PRETTY_FUNCTION__ , ##arg);} while(0)
#define ERROR_R0(fmt, arg...) do{ERROR(fmt , ##arg); return 0;} while(0)
#define ERROR_R(fmt, arg...)  do{ERROR(fmt , ##arg); return;} while(0)
#define ERROR_R_1(fmt, arg...)do{ERROR(fmt , ##arg); return -1;} while(0)
#define ERROR_RX(r,fmt,arg...)do{ERROR(fmt , ##arg); return r;} while(0)
#define CLASS_INIT(name)      static const char * dbg_ ## name ## _name=#name ; static int dbg_ ## name ## _cont = 0 ; extern int dbg_mem_heap;
#define CLASS_CTOR(name)      do{++dbg_##name##_cont; dbg_mem_heap+=sizeof(*this); DEBUG("%p CTOR of %s: %d instances (heap %d)"RED_BOLD" %s"RESET, \
				       this, dbg_##name##_name, dbg_##name##_cont, dbg_mem_heap, (dbg_##name##_cont==1)?#name:"");}while(0)
#define CLASS_DTOR(name)      do{--dbg_##name##_cont; dbg_mem_heap-=sizeof(*this); DEBUG("%p DTOR of %s: %d instances (heap %d)"WHITE" %s"RESET, \
				       this, dbg_##name##_name, dbg_##name##_cont, dbg_mem_heap, (!dbg_##name##_cont)?#name:"");}while(0)

#else

#define DEBUG(x, y...)        do {} while(0)
#define ERROR(x, y...)        do {} while(0)
#define ERROR_R0(fmt, arg...) do {return 0;} while(0)
#define ERROR_R(fmt, arg...)  do {return;} while(0)
#define ERROR_R_1(fmt,arg...) do {return -1;} while(0)
#define ERROR_RX(r,fmt,arg...)do {return r;} while(0)
#define CLASS_INIT(name)
#define CLASS_CTOR(name)      do {} while(0)
#define CLASS_DTOR(name)      do {} while(0)

#endif

// package and version
#ifndef PACKAGE
#define PACKAGE "intromit"
#endif

#ifndef VERSION
#define VERSION "unknown"
#endif

// intromit format error messages
#define MSG(fmt, arg...)      do{fprintf(stderr, PACKAGE": "fmt"\n", ##arg);} while(0)
#define MSG_NEOL(fmt, arg...) do{fprintf(stderr, PACKAGE": "fmt, ##arg);} while(0)
#define MSG_R(fmt, arg...)    do{MSG(fmt, ##arg); return;} while(0)
#define MSG_R0(fmt, arg...)   do{MSG(fmt, ##arg); return 0;} while(0)
#define MSG_R1(fmt, arg...)   do{MSG(fmt, ##arg); return 1;} while(0)


// other utils
#define STR(x)  XSTR(x)
#define XSTR(x) #x

// recursive utils
// takes 0 constant parameter, 0 variable param. and 1 incrementing param
#define FR0000(n, off) n(0##off)
#define FR0007(n, off) FR0000(n,off##0)FR0000(n,off##1)FR0000(n,off##2)FR0000(n,off##3)\
                       FR0000(n,off##4)FR0000(n,off##5)FR0000(n,off##6)FR0000(n,off##7)
#define FR0063(n, off) FR0007(n,off##0)FR0007(n,off##1)FR0007(n,off##2)FR0007(n,off##3)\
                       FR0007(n,off##4)FR0007(n,off##5)FR0007(n,off##6)FR0007(n,off##7)
#define FR0511(n, off) FR0063(n,off##0)FR0063(n,off##1)FR0063(n,off##2)FR0063(n,off##3)\
                       FR0063(n,off##4)FR0063(n,off##5)FR0063(n,off##6)FR0063(n,off##7)

//@}
#endif

/* Offline metadata attributes:

   @metadata_attrs(
	util
	{
		fast_checksum:
					~select
	}
   )
*/
